#include "Stdafx.h"
#include "Logger.h"

#ifdef WIN32
#include <psapi.h>
#pragma comment (lib, "psapi.lib")
#endif // WIN32

Alg::Logger Alg::Logger::s_logger;

void StdWrite(const char * msg, void *)
{
    std::cout << msg;
}

Alg::Logger::Logger()
: _callback(0)
, _user_data(0)
, _level(Verbose)
, _enable_thread_id(true)
, _enable_timestamp(false)
, _enable_prefix(true)
{
}

void Alg::Logger::SetLevel(Level level_)
{
    if (level_ > Verbose)
        throw std::runtime_error("invalid logging level");
    _level = level_;
}

void Alg::Logger::Set(LoggerCallback_t callback, void * user_data)
{
    _callback = 0; // thread safe.
    _user_data = user_data;
    _callback = callback;
}

void Alg::Logger::Set(LoggerCallback_t callback, void * user_data, Level level)
{
    Set(callback, user_data);
    SetLevel(level);
}

void Alg::Logger::SetEnableThreadId(bool enabled)
{
    _enable_thread_id = enabled;
}
void Alg::Logger::SetEnableTimestamp(bool enabled)
{
    _enable_timestamp = enabled;
}
void Alg::Logger::SetEnablePrefix(bool enabled)
{
    _enable_prefix = enabled;
}


void Alg::Logger::SetStd()
{
    _callback = StdWrite;
}

void Alg::Logger::Write(Level level, const std::string & message) const
{
    if (_callback == 0)
        return;

    if (_level < level)
        return;

    std::stringstream ss;

    if (_enable_thread_id)
{
        ss << "[" << boost::this_thread::get_id() << "] ";
}

    if (_enable_prefix)
        ss << GetPrefix(level) << " ";


    if (_enable_timestamp)
{
        std::time_t time_since_epoch;
        std::time( &time_since_epoch );   // get the time since epoch
        std::tm *tm = std::localtime( &time_since_epoch );  // convert to broken-down local time
        if (tm != 0)
        {
            ss  << std::setw(2) << std::setfill(ss.widen('0')) << tm->tm_hour << ":"
                << std::setw(2) << std::setfill(ss.widen('0')) << tm->tm_min << ":"
                << std::setw(2) << std::setfill(ss.widen('0')) << tm->tm_sec << " ";
        }
}
    ss << message;
    ss << std::endl;
    if (_callback != 0)  
{
        _callback(ss.str().c_str(), _user_data);
    }
}

// static 
const char *Alg::Logger::GetPrefix( Level level_ )
{
	switch (level_)
	{
		case Error :
			return "E ";
		case Warning:
			return "W ";
		case Info:
			return "I ";
		case Verbose:
			return "V ";
    case Debug:
        return "D ";
    case Silent:
        return "S ";
	}
	BOOST_ASSERT(!"invalid level");
	return "  ";
}

#ifdef WIN32
void Alg::Logger::DumpMemoryUsage()
{
	static const int BYTES_IN_MEGABYTE = 1024 * 1024;

	HANDLE hProcess = ::GetCurrentProcess();
	PROCESS_MEMORY_COUNTERS pmc;

	if (::GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc)))
	{
		std::stringstream ss;
        ss << "PagefileUsage: " << pmc.PagefileUsage / BYTES_IN_MEGABYTE << " Mb" << std::endl;
        ss << "PeakPagefileUsage: " << pmc.PeakPagefileUsage / BYTES_IN_MEGABYTE << " Mb" << std::endl;

        Write(Info, ss.str());
	}
}
#endif

Alg::Scope::Scope(const char * ctx_) : _ctx(ctx_) 
{ 
    ALG_LOG_SS(Verbose, _ctx << " started..."); 
}
Alg::Scope::~Scope() 
{ 
    ALG_LOG_SS(Verbose, _ctx << " finished."); 
}
